package com.kancy.delay.queue.redis.config;

import brave.propagation.CurrentTraceContext;
import com.kancy.delay.queue.redis.handler.EmptyDelayQueueMessageHandler;
import com.kancy.delay.queue.redis.handler.ReenterDelayQueueExceptionHandler;
import com.kancy.delay.queue.redis.handler.RetryDelayQueueExceptionHandler;
import com.kancy.delay.queue.redis.key.DefaultRedisKeyResolver;
import com.kancy.delay.queue.redis.key.RedisKeyResolver;
import com.kancy.delay.queue.redis.properties.DelayQueueProperties;
import com.kancy.delay.queue.redis.service.DelayQueueClient;
import com.kancy.delay.queue.redis.service.DelayQueueServer;
import com.kancy.delay.queue.redis.service.impl.DelayQueueClientImpl;
import com.kancy.delay.queue.redis.service.impl.DelayQueueServerImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.sleuth.autoconfig.SleuthProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.connection.RedisConnectionFactory;

/**
 * <p>
 * RedisDelayQueueAutoConfiguration
 * <p>
 *
 * @author: kancy
 * @date: 2020/3/4 20:39
 **/
@Import(RedisDelayQueueAutoConfiguration.TraceConfig.class)
public class RedisDelayQueueAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public DelayQueueRedisTemplate delayQueueRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        return new DelayQueueRedisTemplate(redisConnectionFactory);
    }

    @Bean
    @ConfigurationProperties(prefix = "delay.queue")
    public DelayQueueProperties delayQueueProperties(){
        return new DelayQueueProperties();
    }

    @Bean(destroyMethod = "destroy")
    @ConditionalOnMissingBean
    public DelayQueueTaskExecutor delayQueueTaskExecutor(DelayQueueProperties delayQueueProperties){
        return new DelayQueueTaskExecutor(delayQueueProperties);
    }

    @Bean
    public EmptyDelayQueueMessageHandler emptyDelayQueueMessageHandler() {
        return new EmptyDelayQueueMessageHandler();
    }

    @Bean
    @ConditionalOnMissingBean
    public RedisKeyResolver redisKeyResolver() {
        return new DefaultRedisKeyResolver();
    }

    @Bean
    @ConditionalOnMissingBean
    public DelayQueueClient delayQueueClient(DelayQueueRedisTemplate delayQueueRedisTemplate, RedisKeyResolver redisKeyResolver,
                                             DelayQueueProperties delayQueueProperties) {
        return new DelayQueueClientImpl(delayQueueRedisTemplate, redisKeyResolver, delayQueueProperties);
    }

    @Bean(initMethod = "startServer", destroyMethod = "stopServer")
    @ConditionalOnMissingBean
    public DelayQueueServer delayQueueServer(DelayQueueRedisTemplate delayQueueRedisTemplate, RedisKeyResolver redisKeyResolver,
                                             DelayQueueProperties delayQueueProperties, DelayQueueTaskExecutor delayQueueTaskExecutor) {
        return new DelayQueueServerImpl(delayQueueRedisTemplate, redisKeyResolver,delayQueueProperties, delayQueueTaskExecutor);
    }

    @Bean
    @ConditionalOnMissingBean
    public ReenterDelayQueueExceptionHandler reenterDelayQueueExceptionHandler(DelayQueueClient delayQueueClient, DelayQueueProperties delayQueueProperties) {
        return new ReenterDelayQueueExceptionHandler(delayQueueClient, delayQueueProperties);
    }

    @Bean
    @ConditionalOnMissingBean
    public RetryDelayQueueExceptionHandler retryDelayQueueExceptionHandler(DelayQueueTaskExecutor delayQueueTaskExecutor, DelayQueueProperties delayQueueProperties) {
        return new RetryDelayQueueExceptionHandler(delayQueueTaskExecutor, delayQueueProperties);
    }

    /**
     * TraceConfig
     */
    @ConditionalOnClass({CurrentTraceContext.class, SleuthProperties.class})
    static class TraceConfig {
        @Bean
        public TraceContextResolver traceContextResolver(){
            return new TraceContextResolver();
        }
    }

}
